{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "initial_id",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:07.549175Z",
     "start_time": "2025-01-23T04:11:07.542561Z"
    },
    "collapsed": true,
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:00.825507Z",
     "iopub.status.busy": "2025-01-23T04:19:00.825216Z",
     "iopub.status.idle": "2025-01-23T04:19:06.259359Z",
     "shell.execute_reply": "2025-01-23T04:19:06.258803Z",
     "shell.execute_reply.started": "2025-01-23T04:19:00.825480Z"
    },
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=14, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cu124\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "1dad802b6500ab83",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.128447Z",
     "start_time": "2025-01-23T04:11:07.655671Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:06.260903Z",
     "iopub.status.busy": "2025-01-23T04:19:06.260550Z",
     "iopub.status.idle": "2025-01-23T04:19:08.479957Z",
     "shell.execute_reply": "2025-01-23T04:19:08.479327Z",
     "shell.execute_reply.started": "2025-01-23T04:19:06.260881Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(PosixPath('competitions/cifar-10/train/1.png'), 'frog'),\n",
      " (PosixPath('competitions/cifar-10/train/2.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/3.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/4.png'), 'deer'),\n",
      " (PosixPath('competitions/cifar-10/train/5.png'), 'automobile')]\n",
      "[(PosixPath('competitions/cifar-10/test/1.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/2.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/3.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/4.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/5.png'), 'cat')]\n",
      "50000 300000\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "# 目的：通过读取csv文件，得到图片的类别，并将图片路径和类别保存到DataFrame中。\n",
    "\n",
    "DATA_DIR1 = Path(\"./\")\n",
    "DATA_DIR2=Path(\"./competitions/cifar-10/\")\n",
    "\n",
    "train_labels_file = DATA_DIR1 / \"trainLabels.csv\"\n",
    "test_csv_file = DATA_DIR1 / \"sampleSubmission.csv\"  # 测试集模板csv文件\n",
    "train_folder = DATA_DIR2 / \"train/\"\n",
    "test_folder = DATA_DIR2 / \"test/\"\n",
    "# 所有的类别\n",
    "class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']\n",
    "\n",
    "\n",
    "# filepath:csv文件路径，folder:图片所在文件夹\n",
    "def parse_csv_file(filepath, folder):\n",
    "    result = []\n",
    "    # 读取所有行\n",
    "    # with 语句：用于管理文件的上下文。在 with 块结束时，文件会自动关闭，无需手动调用 f.close()。\n",
    "    with open(filepath, 'r') as f:\n",
    "        # f.readlines()：读取文件的所有行，返回一个列表，每个元素是一行内容。\n",
    "        # 第一行不需要，因为第一行是标题\n",
    "        lines = f.readlines()[1:]\n",
    "    for line in lines:\n",
    "        # strip('\\n')：去除行末的换行符（\\n）。\n",
    "        # split(',')：按','分割字符串，返回一个列表。\n",
    "        image_id, label_str = line.strip('\\n').split(',')\n",
    "        # 得到图片的路径\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "        # 得到对应图片的路径和分类\n",
    "        result.append((image_full_path, label_str))\n",
    "    return result\n",
    "\n",
    "\n",
    "# 得到训练集和测试集的图片路径和分类\n",
    "train_labels_info = parse_csv_file(train_labels_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "\n",
    "#打印\n",
    "import pprint\n",
    "\n",
    "pprint.pprint(train_labels_info[0:5])\n",
    "pprint.pprint(test_csv_info[0:5])\n",
    "print(len(train_labels_info), len(test_csv_info))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8cd5063c39c678cf",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.202105Z",
     "start_time": "2025-01-23T04:11:09.129462Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:08.481259Z",
     "iopub.status.busy": "2025-01-23T04:19:08.480726Z",
     "iopub.status.idle": "2025-01-23T04:19:08.542992Z",
     "shell.execute_reply": "2025-01-23T04:19:08.542474Z",
     "shell.execute_reply.started": "2025-01-23T04:19:08.481228Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            filepath       class\n",
      "0  competitions/cifar-10/train/1.png        frog\n",
      "1  competitions/cifar-10/train/2.png       truck\n",
      "2  competitions/cifar-10/train/3.png       truck\n",
      "3  competitions/cifar-10/train/4.png        deer\n",
      "4  competitions/cifar-10/train/5.png  automobile\n",
      "                                filepath       class\n",
      "0  competitions/cifar-10/train/45001.png       horse\n",
      "1  competitions/cifar-10/train/45002.png  automobile\n",
      "2  competitions/cifar-10/train/45003.png        deer\n",
      "3  competitions/cifar-10/train/45004.png  automobile\n",
      "4  competitions/cifar-10/train/45005.png    airplane\n",
      "                           filepath class\n",
      "0  competitions/cifar-10/test/1.png   cat\n",
      "1  competitions/cifar-10/test/2.png   cat\n",
      "2  competitions/cifar-10/test/3.png   cat\n",
      "3  competitions/cifar-10/test/4.png   cat\n",
      "4  competitions/cifar-10/test/5.png   cat\n"
     ]
    }
   ],
   "source": [
    "# 取前45000张图片作为训练集\n",
    "train_df = pd.DataFrame(train_labels_info[0:45000])\n",
    "# 取后5000张图片作为验证集\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:])\n",
    "# 测试集\n",
    "test_df = pd.DataFrame(test_csv_info)\n",
    "\n",
    "# 为 Pandas DataFrame 的列重新命名\n",
    "train_df.columns = ['filepath', 'class']\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']\n",
    "\n",
    "print(train_df.head())\n",
    "print(valid_df.head())\n",
    "print(test_df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "af9444393c2debca",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.211908Z",
     "start_time": "2025-01-23T04:11:09.203117Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:08.543945Z",
     "iopub.status.busy": "2025-01-23T04:19:08.543610Z",
     "iopub.status.idle": "2025-01-23T04:19:10.849252Z",
     "shell.execute_reply": "2025-01-23T04:19:10.848721Z",
     "shell.execute_reply.started": "2025-01-23T04:19:08.543923Z"
    }
   },
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision import transforms\n",
    "\n",
    "\n",
    "class Cifar10Dataset(Dataset):\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "    # enumerate(class_names)：遍历 class_names，返回索引和类别名称的元组\n",
    "    # 将类别名称映射为索引，通常用于将标签转换为模型可以处理的数值。\n",
    "    label_to_idx = {\n",
    "        label: idx for idx, label in enumerate(class_names)\n",
    "    }\n",
    "    # 将索引映射为类别名称，通常用于将模型的输出（索引）转换回可读的类别名称\n",
    "    idx_to_label = {\n",
    "        idx: label for idx, label in enumerate(class_names)\n",
    "    }\n",
    "\n",
    "    def __init__(self, mode, transform=None):\n",
    "        # 获取对应模式的df，不同字符串对应不同模式\n",
    "        self.df = self.df_map.get(mode, None)\n",
    "        if self.df is None:\n",
    "            raise ValueError(f\"Invalid mode: {mode}\")\n",
    "        self.transform = transform\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        # 获取图片路径和标签\n",
    "        img_path, label = self.df.iloc[index]\n",
    "        # 打开一张图片并将其转换为 RGB 格式\n",
    "        img = Image.open(img_path).convert('RGB')  # 确保图片具有三个通道\n",
    "        # 应用数据增强\n",
    "        img = self.transform(img)\n",
    "        # label 转换为 idx\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label\n",
    "\n",
    "    def __len__(self):\n",
    "        # 返回df的行数,样本数\n",
    "        return self.df.shape[0]\n",
    "\n",
    "\n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261]\n",
    "\n",
    "#数据增强\n",
    "# ToTensor还将图像的维度从[height, width, channels]转换为[channels, height, width]。\n",
    "transforms_train = transforms.Compose([\n",
    "    transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),  # 缩放\n",
    "    transforms.RandomRotation(40),  # 随机旋转\n",
    "    transforms.RandomHorizontalFlip(),  # 随机水平翻转\n",
    "    transforms.ToTensor(),  # 转换为Tensor\n",
    "    transforms.Normalize(mean, std)  # 标准化\n",
    "])\n",
    "\n",
    "transforms_eval = transforms.Compose([\n",
    "    transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize(mean, std)\n",
    "])\n",
    "\n",
    "train_ds = Cifar10Dataset(mode=\"train\", transform=transforms_train)\n",
    "eval_ds = Cifar10Dataset(mode=\"eval\", transform=transforms_eval)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d17ef4a56f0b6ae1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.219746Z",
     "start_time": "2025-01-23T04:11:09.213913Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.850293Z",
     "iopub.status.busy": "2025-01-23T04:19:10.849880Z",
     "iopub.status.idle": "2025-01-23T04:19:10.935472Z",
     "shell.execute_reply": "2025-01-23T04:19:10.934923Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.850271Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([3, 32, 32])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_ds[0][0].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "161282a4e612afcd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.224639Z",
     "start_time": "2025-01-23T04:11:09.220761Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.936212Z",
     "iopub.status.busy": "2025-01-23T04:19:10.936026Z",
     "iopub.status.idle": "2025-01-23T04:19:10.939224Z",
     "shell.execute_reply": "2025-01-23T04:19:10.938779Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.936192Z"
    }
   },
   "outputs": [],
   "source": [
    "batch_size = 64\n",
    "\n",
    "train_loader = DataLoader(train_ds, batch_size=batch_size,\n",
    "                          shuffle=True)\n",
    "eval_loader = DataLoader(eval_ds, batch_size=batch_size,\n",
    "                         shuffle=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20b5b31416450980",
   "metadata": {},
   "source": [
    "## 模型定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b73daeeb83b4b527",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.231755Z",
     "start_time": "2025-01-23T04:11:09.225643Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.941462Z",
     "iopub.status.busy": "2025-01-23T04:19:10.941088Z",
     "iopub.status.idle": "2025-01-23T04:19:10.947242Z",
     "shell.execute_reply": "2025-01-23T04:19:10.946803Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.941442Z"
    }
   },
   "outputs": [],
   "source": [
    "class Resdiual(nn.Module):\n",
    "    \"\"\"\n",
    "    浅层的残差块，无bottleneck（性能限制\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, input_channels, output_channels,\n",
    "                 use_1x1conv=False, stride=1):\n",
    "        \"\"\"\n",
    "        残差块\n",
    "        params filters: 过滤器数目，决定输出通道\n",
    "        params use_1x1conv: 是否使用 1x1 卷积，此时 stride=2，进行降采样\n",
    "        params strides: 步长，默认为1，当降采样的时候设置为2\n",
    "        \"\"\"\n",
    "        super().__init__()\n",
    "        # [1+(n+2-3)]//1=n \n",
    "        # [1+(n+2-3)]//2=n//2\n",
    "        # 即该方法可能会降采样\n",
    "        self.conv1 = nn.Conv2d(\n",
    "            in_channels=input_channels,\n",
    "            out_channels=output_channels,\n",
    "            kernel_size=3,\n",
    "            stride=stride,\n",
    "            padding=1\n",
    "        )\n",
    "        # [1+(n+2-3)]//1=n \n",
    "        self.conv2 = nn.Conv2d(\n",
    "            in_channels=output_channels,\n",
    "            out_channels=output_channels,\n",
    "            kernel_size=3,\n",
    "            stride=1,\n",
    "            padding=1\n",
    "        )\n",
    "        if use_1x1conv:\n",
    "            # skip connection 的 1x1 卷积，用于改变通道数和降采样，使得最终可以做残差连接\n",
    "            # [1+n-1]//s=n//s\n",
    "            self.conv_sc = nn.Conv2d(\n",
    "                in_channels=input_channels,\n",
    "                out_channels=output_channels,\n",
    "                kernel_size=1,\n",
    "                stride=stride\n",
    "            )\n",
    "        else:\n",
    "            self.conv_sc = None\n",
    "\n",
    "        self.bn1 = nn.BatchNorm2d(output_channels, eps=1e-5, momentum=0.9)\n",
    "        self.bn2 = nn.BatchNorm2d(output_channels, eps=1e-5, momentum=0.9)\n",
    "\n",
    "    def forward(self, inputs):\n",
    "        flow = F.relu(self.bn1(self.conv1(inputs)))  # 卷积->BN->ReLU\n",
    "        flow = self.bn2(self.conv2(flow))  # 卷积->BN\n",
    "        if self.conv_sc:\n",
    "            inputs = self.conv_sc(inputs)  # 1x1卷积，改变通道数和降采样\n",
    "        # 残差连接->ReLU，必须保证flow和inputs的shape相同\n",
    "        return F.relu(flow + inputs)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "fc16467b5391fd55",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.237701Z",
     "start_time": "2025-01-23T04:11:09.232758Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.947909Z",
     "iopub.status.busy": "2025-01-23T04:19:10.947745Z",
     "iopub.status.idle": "2025-01-23T04:19:10.952290Z",
     "shell.execute_reply": "2025-01-23T04:19:10.951856Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.947891Z"
    }
   },
   "outputs": [],
   "source": [
    "class ResdiualBlock(nn.Module):\n",
    "    \"\"\"\n",
    "    若干个 Resdiual 模块堆叠在一起，\n",
    "    通常在第一个模块给 skip connection 使用 1x1conv with stride=2\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, input_channels, output_channels, num, is_first=False):\n",
    "        \"\"\"\n",
    "        params filters: 过滤器数目\n",
    "        params num: 堆叠几个 Resdiual 模块\n",
    "        params is_first: 是不是第一个block。 最上面一层 Resdiual 的 stride=1,is_first=False,图像尺寸减半，False图像尺寸不变\n",
    "        \"\"\"\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential()  # 用于存放 Resdiual 模块\n",
    "        # append() 等价于 add_module()\n",
    "        self.model.append(Resdiual(\n",
    "            input_channels=input_channels,\n",
    "            output_channels=output_channels,\n",
    "            use_1x1conv=not is_first,\n",
    "            stride=1 if is_first else 2\n",
    "        ))  # 第一个 Resdiual 模块，负责通道翻倍,图像的尺寸减半\n",
    "        for _ in range(1, num):\n",
    "            # 堆叠 num 个 Resdiual 模块\n",
    "            self.model.append(Resdiual(\n",
    "                input_channels=output_channels,\n",
    "                output_channels=output_channels,\n",
    "                use_1x1conv=False,\n",
    "                stride=1\n",
    "            ))\n",
    "\n",
    "    def forward(self, inputs):\n",
    "        return self.model(inputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "8128761d5d6c0e1d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.245913Z",
     "start_time": "2025-01-23T04:11:09.238703Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.953023Z",
     "iopub.status.busy": "2025-01-23T04:19:10.952859Z",
     "iopub.status.idle": "2025-01-23T04:19:10.960075Z",
     "shell.execute_reply": "2025-01-23T04:19:10.959593Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.953005Z"
    }
   },
   "outputs": [],
   "source": [
    "class ResNetCifar10(nn.Module):\n",
    "    def __init__(self, n=3, num_classes=10):\n",
    "        \"\"\"\n",
    "        params units: 预测类别的数目\n",
    "        \"\"\"\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            # conv1\n",
    "            nn.Conv2d(in_channels=3, out_channels=16,\n",
    "                      kernel_size=3, stride=1),\n",
    "            nn.BatchNorm2d(16, momentum=0.9, eps=1e-5),\n",
    "            nn.ReLU(),\n",
    "            # conv2_x\n",
    "            ResdiualBlock(input_channels=16, output_channels=16,\n",
    "                          num=2 * n, is_first=True),\n",
    "            # conv3_x\n",
    "            ResdiualBlock(input_channels=16, output_channels=32,\n",
    "                          num=2 * n),\n",
    "            # conv4_x\n",
    "            ResdiualBlock(input_channels=32, output_channels=64,\n",
    "                          num=2 * n),\n",
    "            # 全局平均池化层\n",
    "            #无论输入图片大小，输出都是1x1，把width和height压缩为1\n",
    "            nn.AdaptiveAvgPool2d((1, 1)),\n",
    "            # 全连接层\n",
    "            nn.Flatten(),  # 64*1*1 -> 64\n",
    "        )\n",
    "        # 输出层\n",
    "        self.cls = nn.Linear(in_features=64, out_features=num_classes)\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                # Kaiming 初始化（也称为 He 初始化）是为深度神经网络设计的一种初始化方法，特别适用于 ReLU 激活函数。\n",
    "                nn.init.kaiming_uniform_(m.weight)\n",
    "                if m.bias is not None:\n",
    "                    nn.init.zeros_(m.bias)\n",
    "\n",
    "    @classmethod  # 类方法，可以直接通过类名调用\n",
    "    def from_pretrained(cls, ckpt_path, num_classes=10):\n",
    "        state_dict = torch.load(ckpt_path, map_location=device)  # 加载模型参数\n",
    "        state_dict.pop(\"cls.weight\")  # 去掉最后一层的权重\n",
    "        state_dict.pop(\"cls.bias\")  # 去掉最后一层的偏置\n",
    "\n",
    "        model = cls(num_classes=num_classes)  # 实例化模型\n",
    "        # 将修改后的状态字典加载到新创建的模型实例中\n",
    "        # 参数strict=False表示在加载状态字典时，如果字典中存在模型不期望的键或缺少某些期望的键，将不会抛出错误。这在迁移学习中很有用，因为你可能希望覆盖或忽略一些权重。\n",
    "        model.load_state_dict(state_dict, strict=False)  # 加载模型参数\n",
    "        return model\n",
    "\n",
    "    def forward(self, inputs):\n",
    "        features = self.model(inputs)\n",
    "        return self.cls(features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "bb519b4756d62090",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.298554Z",
     "start_time": "2025-01-23T04:11:09.246916Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.960792Z",
     "iopub.status.busy": "2025-01-23T04:19:10.960625Z",
     "iopub.status.idle": "2025-01-23T04:19:10.962785Z",
     "shell.execute_reply": "2025-01-23T04:19:10.962327Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.960774Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# for key, value in ResNetCifar10(len(class_names)).named_parameters():\n",
    "#     print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b294d25e7f6287d0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.345501Z",
     "start_time": "2025-01-23T04:11:09.300574Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:10.963523Z",
     "iopub.status.busy": "2025-01-23T04:19:10.963243Z",
     "iopub.status.idle": "2025-01-23T04:19:11.025126Z",
     "shell.execute_reply": "2025-01-23T04:19:11.024688Z",
     "shell.execute_reply.started": "2025-01-23T04:19:10.963505Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total trainable parameters: 1929546\n"
     ]
    }
   ],
   "source": [
    "total_params = sum(p.numel() for p in ResNetCifar10(len(class_names)).parameters() if p.requires_grad)\n",
    "print(f\"Total trainable parameters: {total_params}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76ca49d0dca74376",
   "metadata": {},
   "source": [
    "## 模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "632d31ce33563b0c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.464033Z",
     "start_time": "2025-01-23T04:11:09.346514Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:11.025962Z",
     "iopub.status.busy": "2025-01-23T04:19:11.025631Z",
     "iopub.status.idle": "2025-01-23T04:19:11.126576Z",
     "shell.execute_reply": "2025-01-23T04:19:11.126062Z",
     "shell.execute_reply.started": "2025-01-23T04:19:11.025943Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "@torch.no_grad()  # 装饰器，禁止梯度计算\n",
    "def evaluate(model, data_loader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in data_loader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "\n",
    "        # 前向传播\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)  # 验证集损失\n",
    "        # tensor.item() 获取tensor的数值，loss是只有一个元素的tensor\n",
    "        loss_list.append(loss.item())\n",
    "\n",
    "        # 预测\n",
    "        preds = logits.argmax(axis=-1)  # 预测类别\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())  # tensor转numpy，再转list\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "\n",
    "    acc = accuracy_score(label_list, pred_list)  # 计算准确率\n",
    "    return np.mean(loss_list), acc  # # 返回验证集平均损失和准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "28c2ba49f4ff546",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.471082Z",
     "start_time": "2025-01-23T04:11:09.466036Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:11.127474Z",
     "iopub.status.busy": "2025-01-23T04:19:11.127171Z",
     "iopub.status.idle": "2025-01-23T04:19:11.132672Z",
     "shell.execute_reply": "2025-01-23T04:19:11.132216Z",
     "shell.execute_reply.started": "2025-01-23T04:19:11.127453Z"
    }
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=500, save_best_only=True):\n",
    "        self.save_dir = save_dir  # 保存路径\n",
    "        self.save_step = save_step  # 保存步数\n",
    "        self.save_best_only = save_best_only  # 是否只保存最好的模型\n",
    "        self.best_metric = -1  # 最好的指标，指标不可能为负数，所以初始化为-1\n",
    "        # 创建保存路径\n",
    "        if not os.path.exists(self.save_dir):  # 如果不存在保存路径，则创建\n",
    "            os.makedirs(self.save_dir)\n",
    "\n",
    "    # 对象被调用时：当你将对象像函数一样调用时，Python 会自动调用 __call__ 方法。\n",
    "    # state_dict() 返回模型参数的字典，包括模型参数和优化器参数\n",
    "    # metric 是指标，可以是验证集的准确率，也可以是其他指标\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return  # 不是保存步数，则直接返回\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None  # 必须传入metric\n",
    "            if metric >= self.best_metric:  # 如果当前指标大于最好的指标\n",
    "                # save checkpoint\n",
    "                # 保存最好的模型，覆盖之前的模型，不保存step，只保存state_dict，即模型参数，不保存优化器参数\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"08_resnet_fine_tuning.ckpt\"))\n",
    "                self.best_metric = metric  # 更新最好的指标\n",
    "        else:\n",
    "            # 保存模型\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "            # 保存每个step的模型，不覆盖之前的模型，保存step，保存state_dict，即模型参数，不保存优化器参数\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "cd4d61586ad24eb5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.476996Z",
     "start_time": "2025-01-23T04:11:09.472086Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:11.133485Z",
     "iopub.status.busy": "2025-01-23T04:19:11.133188Z",
     "iopub.status.idle": "2025-01-23T04:19:11.137325Z",
     "shell.execute_reply": "2025-01-23T04:19:11.136897Z",
     "shell.execute_reply.started": "2025-01-23T04:19:11.133465Z"
    }
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        self.patience = patience  # 多少个step没有提升就停止训练\n",
    "        self.min_delta = min_delta  # 最小的提升幅度\n",
    "        self.best_metric = -1  # 记录的最好的指标\n",
    "        self.counter = 0  # 计数器，记录连续多少个step没有提升\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:  # 如果指标提升了\n",
    "            self.best_metric = metric  # 更新最好的指标\n",
    "            self.counter = 0  # 计数器清零\n",
    "        else:\n",
    "            self.counter += 1  # 计数器加一\n",
    "\n",
    "    @property  # 使用@property装饰器，使得 对象.early_stop可以调用，不需要()\n",
    "    def early_stop(self):\n",
    "        # 如果计数器大于等于patience，则返回True，停止训练\n",
    "        return self.counter >= self.patience"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "725cf8a521379801",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.486088Z",
     "start_time": "2025-01-23T04:11:09.478Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:11.138151Z",
     "iopub.status.busy": "2025-01-23T04:19:11.137931Z",
     "iopub.status.idle": "2025-01-23T04:19:11.146530Z",
     "shell.execute_reply": "2025-01-23T04:19:11.146076Z",
     "shell.execute_reply.started": "2025-01-23T04:19:11.138133Z"
    }
   },
   "outputs": [],
   "source": [
    "def training(model,\n",
    "             train_loader,\n",
    "             val_loader,\n",
    "             epoch,\n",
    "             loss_fct,\n",
    "             optimizer,\n",
    "             save_ckpt_callback=None,\n",
    "             early_stop_callback=None,\n",
    "             eval_step=500,\n",
    "             ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 0  # 全局步数\n",
    "    model.train()  # 训练模式\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "\n",
    "                # 前向传播\n",
    "                logits = model(datas)\n",
    "                loss = loss_fct(logits, labels)  # 训练集损失\n",
    "                preds = logits.argmax(axis=-1)  # 预测类别\n",
    "\n",
    "                # 反向传播\n",
    "                optimizer.zero_grad()  # 梯度清零\n",
    "                loss.backward()  # 反向传播\n",
    "                optimizer.step()  # 优化器更新参数\n",
    "\n",
    "                # 计算准确率\n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n",
    "                loss = loss.cpu().item()\n",
    "\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss,\n",
    "                    \"acc\": acc,\n",
    "                    \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # 评估\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()  # 评估模式\n",
    "                    # 验证集损失和准确率\n",
    "                    val_loss, val_acc = evaluate(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss,\n",
    "                        \"acc\": val_acc,\n",
    "                        \"step\": global_step\n",
    "                    })\n",
    "                    model.train()  # 训练模式\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        # model.state_dict() 返回模型参数的字典，包括模型参数和优化器参数\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), val_acc)\n",
    "                        # 保存最好的模型，覆盖之前的模型，保存step，保存state_dict,通过metric判断是否保存最好的模型\n",
    "\n",
    "                    # 3. 早停 early stopping\n",
    "                    if early_stop_callback is not None:\n",
    "                        # 验证集准确率不再提升，则停止训练\n",
    "                        early_stop_callback(val_acc)\n",
    "                        # 验证集准确率不再提升，则停止训练\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict  # 早停，返回记录字典 record_dict\n",
    "\n",
    "                # 更新进度条和全局步数\n",
    "                pbar.update(1)  # 更新进度条\n",
    "                global_step += 1  # 全局步数加一\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "\n",
    "    return record_dict  # 训练结束，返回记录字典 record_dict\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "22bf1e82c9715088",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:09.540116Z",
     "start_time": "2025-01-23T04:11:09.487096Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:11.147453Z",
     "iopub.status.busy": "2025-01-23T04:19:11.147033Z",
     "iopub.status.idle": "2025-01-23T04:19:11.327727Z",
     "shell.execute_reply": "2025-01-23T04:19:11.327208Z",
     "shell.execute_reply.started": "2025-01-23T04:19:11.147434Z"
    }
   },
   "outputs": [],
   "source": [
    "epoch = 100\n",
    "\n",
    "# 第一次训练\n",
    "model = ResNetCifar10(len(class_names))  # 定义模型\n",
    "model = model.to(device)  # 将模型移到GPU上\n",
    "\n",
    "# 1. 定义损失函数 采用MSE损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "\n",
    "# 2. 定义优化器 Adam\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 3.save model checkpoint\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(save_dir=\"checkpoints\", save_step=len(train_loader), save_best_only=True)\n",
    "\n",
    "# 4. early stopping\n",
    "early_stop_callback = EarlyStopCallback(patience=5, min_delta=0.01)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "5335f62fe5e4977f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-23T04:11:48.566286Z",
     "start_time": "2025-01-23T04:11:09.541118Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:19:11.328736Z",
     "iopub.status.busy": "2025-01-23T04:19:11.328345Z",
     "iopub.status.idle": "2025-01-23T04:39:07.989549Z",
     "shell.execute_reply": "2025-01-23T04:39:07.989041Z",
     "shell.execute_reply.started": "2025-01-23T04:19:11.328715Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 22%|██▏       | 15488/70400 [19:56<1:10:42, 12.94it/s, epoch=21]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 22 / global_step 15488\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# 训练过程\n",
    "record_dict = training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    eval_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_loader)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "1a790e5f4635d5e8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T04:39:07.990485Z",
     "iopub.status.busy": "2025-01-23T04:39:07.990276Z",
     "iopub.status.idle": "2025-01-23T04:39:08.187914Z",
     "shell.execute_reply": "2025-01-23T04:39:08.187333Z",
     "shell.execute_reply.started": "2025-01-23T04:39:07.990463Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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C8jEpsST2KgymojAq6++SqtWrXCdVFDkkksu4cYbb2Tbtm1ccsklJCUlERUVxeDBg5k/f36dH/ell16iU6dO2Gw2unXrxttvv+3ZZxgGjzzyCG3btiU0NJRWrVpx5513eva/+OKLdOnShbCwMJKSkrjyyivrHI/IiRrjdXHo0CGuvvpqWrduTUREBL179+b9998vd4zL5eKpp56ic+fOhIaG0rZtW/7xj3949u/Zs4err76ahIQEIiMjGTRoED///HPtn7g0GYZh8N+lGWw8WrP1WwJBWW9Nx+ZRhNss9XLNyed0wRZiZtmOw/y4NbterumvAjKx8fTYaCiaSMMyDPfrzBc3L751uvLKKzl06BDfffedZ9vhw4eZO3cu1157LXl5eYwZM4YFCxawatUqzj//fMaOHUtGRkaV17zhhhv43e9+V+X+Tz/9lLvuuos///nPrF27lj/96U9MnDjRE8PHH3/Ms88+yyuvvMKWLVv47LPP6N27NwC//PILd955J4899hibNm1i7ty5nHXWWTV+vuIHKnttOAqC7nVRVFTEwIED+frrr1m7di233HIL1113HcuWLfMcM2XKFJ588kkefPBB1q9fz3vvvUdSUhIAeXl5nH322ezdu5cvvviCX3/9lfvuu69CMiaBafnOIzz+9Ube3GymxBkcbb52r7twwGn1MAytTHJsGNcObQvAXz9ew5F8e71d29/UfLWfJkRD0UQaiaMAnqhdKco6+9s+sEXW6ND4+HguuOAC3nvvPc477zwAPvroIxITEznnnHMwm8307dvXc/zjjz/Op59+yhdffMHkyZMrvWbLli2r/XD1zDPPcMMNN3D77bcDkJaWxtKlS3nmmWc455xzyMjIIDk5mREjRmC1Wmnbti1DhgwBICMjg8jISC666CKio6Np164dffv2JTc3uFaQbtJOem2YgbjGeFw/e120bt2ae++913P/jjvu4Ntvv+XDDz9kyJAhHDt2jOeee45///vfTJgwAYBOnTpxxhlnAPDee+9x8OBBli9fTkJCAgCdO3f24g8iTdlPpb0LhU4T6/YfY1CHUB9H1PCOz6+pW+GAk90zsiv/23iAXYcKSPtwNTMnDMZsDryesIDssSlRj42InOTaa6/l448/pri4GIB3332X3//+95jNZvLy8rj33nvp0aMHcXFxREVFsWHDhmq/mZ46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sRERERERkbynxEZERERERPLekF2g83QZYwDo7u4+rccnk0mi0Sjd3d14vd4zWTU5AxSf3KXY5Lbhik//Z2//Z7FkqG06eyk2uU3xyV252C7lXGITDocBqK2tHeGaiIiMXuFwmJKSkpGuRs5Q2yQiMrJOpl2yTI79W851XZqamiguLsayrFN+fHd3N7W1tezdu5dQKDQENZRPQvHJXYpNbhuu+BhjCIfDjBs3DtvWaOV+apvOXopNblN8clcutks512Nj2zYTJkz4xMcJhUI6AXKY4pO7FJvcNhzxUU/N0dQ2nf0Um9ym+OSuXGqX9O84ERERERHJe0psREREREQk7511iY3f72f58uX4/f6Rroocg+KTuxSb3Kb45DfFL3cpNrlN8clduRibnJs8QERERERE5FSddT02IiIiIiIy+iixERERERGRvKfERkRERERE8t5ZndhYlsWzzz470tWQIygu+WX37t1YlsXbb7890lWRIyg2+UmfgblJcckv+vzLXSMZm7xPbB577DHq6+spKChgzpw5vPnmmyNdpVHvvvvuw7KsAeWCCy4Y6WqNWq+88gpf/OIXGTdu3DEbbmMM9957LzU1NQQCAebPn8+OHTtGprKjzIlic9tttx11Li1atGhkKiunRG1T7lHblFvUNuWufG6b8jqxWbt2LcuWLWP58uW89dZbzJgxg4ULF9LW1jbSVRv1LrroIpqbm7Pl1VdfHekqjVo9PT3MmDGDxx577Jj3P/jgg/zyl79k9erVbNq0icLCQhYuXEgsFhvmmo4+J4oNwKJFiwacS3/4wx+GsYZyOtQ25S61TblDbVPuyue2Ka8Tm5UrV3LnnXeyZMkSpk6dyurVqwkGg6xZs+aY+y9fvpyamhq2bt06zDUdfTweD9XV1dlSWVk56L6Ky9BavHgxP/3pT7n22muPus8Yw6pVq/jhD3/I1VdfzfTp03nyySdpamoadEhGOp3mq1/9KhdccAF79uwZ4tqf3Y4Xm35+v3/AuVRWVjbovopNblDblLvUNuUOtU25K5/bprxNbBKJBJs3b2b+/PnZbbZtM3/+fDZu3DhgX2MM3/jGN3jyySfZsGED06dPH+7qjjo7duxg3LhxTJ48mZtvvvmYf8iKy8hrbGykpaVlwHlUUlLCnDlzjjqPAOLxONdffz1vv/02GzZsYOLEicNZ3VGpoaGBsWPHcv7553PXXXfR0dFxzP0Um9ygtim3qW3KD2qbcl+utk2eIT36EGpvbyedTlNVVTVge1VVFdu2bcuup1IpvvKVr7BlyxZeffVVxo8fP9xVHXXmzJnDE088wfnnn09zczMrVqzgM5/5DP/5z38oLi4GFJdc0dLSAnDM86j/vn6RSIQvfOELxONxXnrpJUpKSoatnqPVokWLuO6665g0aRK7du3i+9//PosXL2bjxo04jpPdT7HJHWqbcpfapvyhtim35XLblLeJzcn61re+hd/v54033jhul7OcOYsXL84uT58+nTlz5lBXV8cf//hHbr/9dkBxyUc33XQTEyZM4J///CeBQGCkqzMq3HjjjdnladOmMX36dM455xwaGhqYN29e9j7FJv/oM3D4qW06O+nzb/jlctuUt0PRKisrcRyH1tbWAdtbW1uprq7Orl9xxRXs37+fv//978NdRelTWlrKeeedx86dO7PbFJfc0H+unOg8ArjyyivZunXrMYcByPCYPHkylZWVA84lUGxyidqm/KG2KXepbcovudQ25W1i4/P5mDlzJuvXr89uc12X9evXM3fu3Oy2q666it///vfccccdPPXUUyNR1VEvEomwa9cuampqstsUl9wwadIkqqurB5xH3d3dbNq0acB5BHDXXXfxwAMPcNVVV/Hyyy8Pd1UF2LdvHx0dHQPOJVBsconapvyhtil3qW3KLznVNpk89tRTTxm/32+eeOIJ895775mvfe1rprS01LS0tBhjjAHMM888Y4wx5umnnzYFBQXm6aefHsEajw7f/va3TUNDg2lsbDSvvfaamT9/vqmsrDRtbW3GGMVluIXDYbNlyxazZcsWA5iVK1eaLVu2mI8++sgYY8wDDzxgSktLzXPPPWe2bt1qrr76ajNp0iTT29trjDGmsbHRAGbLli3GGGN+/vOfm6KiIrNhw4aReklnjePFJhwOm+985ztm48aNprGx0fzjH/8wl156qTn33HNNLBYzxig2uUptU25S25Rb1Dblrnxum/I6sTHGmEcffdRMnDjR+Hw+M3v2bPPGG29k7/v4h5Qxxqxdu9YUFBSYP//5zyNQ09HjhhtuMDU1Ncbn85nx48ebG264wezcuTN7v+IyvF566SUDHFVuvfVWY4wxruuaH/3oR6aqqsr4/X4zb948s3379uzjj/yAMsaYRx55xBQXF5vXXnttmF/N2eV4sYlGo2bBggVmzJgxxuv1mrq6OnPnnXdmvxwbo9jkMrVNuUdtU25R25S78rltsowxZuj6g0RERERERIZe3v7GRkREREREpJ8SGxERERERyXtKbEREREREJO8psRERERERkbynxEZERERERPKeEhsREREREcl7SmxERERERCTvKbEREREREZG8p8RG5DTcdtttXHPNNSNdDRERkSy1TTLaKbEREREREZG8p8RG5Dj+9Kc/MW3aNAKBABUVFcyfP5+7776b3/zmNzz33HNYloVlWTQ0NACwd+9evvzlL1NaWkp5eTlXX301u3fvzh6v/79pK1asYMyYMYRCIb7+9a+TSCRG5gWKiEjeUdskcmyeka6ASK5qbm7mpptu4sEHH+Taa68lHA6zYcMGbrnlFvbs2UN3dzePP/44AOXl5SSTSRYuXMjcuXPZsGEDHo+Hn/70pyxatIitW7fi8/kAWL9+PQUFBTQ0NLB7926WLFlCRUUFP/vZz0by5YqISB5Q2yQyOCU2IoNobm4mlUpx3XXXUVdXB8C0adMACAQCxONxqqurs/v/9re/xXVdfv3rX2NZFgCPP/44paWlNDQ0sGDBAgB8Ph9r1qwhGAxy0UUX8eMf/5i7776bn/zkJ9i2OlFFRGRwaptEBqe/VJFBzJgxg3nz5jFt2jSuv/56fvWrX3Hw4MFB93/nnXfYuXMnxcXFFBUVUVRURHl5ObFYjF27dg04bjAYzK7PnTuXSCTC3r17h/T1iIhI/lPbJDI49diIDMJxHNatW8frr7/Oiy++yKOPPsoPfvADNm3adMz9I5EIM2fO5He/+91R940ZM2aoqysiIqOA2iaRwSmxETkOy7K47LLLuOyyy7j33nupq6vjmWeewefzkU6nB+x76aWXsnbtWsaOHUsoFBr0mO+88w69vb0EAgEA3njjDYqKiqitrR3S1yIiImcHtU0ix6ahaCKD2LRpE//93//Nv//9b/bs2cNf/vIXDhw4wIUXXkh9fT1bt25l+/bttLe3k0wmufnmm6msrOTqq69mw4YNNDY20tDQwDe/+U327duXPW4ikeD222/nvffe4/nnn2f58uUsXbpUY5hFROSE1DaJDE49NiKDCIVCvPLKK6xatYru7m7q6up45JFHWLx4MbNmzaKhoYFZs2YRiUR46aWXuPzyy3nllVf47ne/y3XXXUc4HGb8+PHMmzdvwH/J5s2bx7nnnstnP/tZ4vE4N910E/fdd9/IvVAREckbaptEBmcZY8xIV0JktLjtttvo6uri2WefHemqiIiIAGqb5Oyh/kUREREREcl7SmxERERERCTvaSiaiIiIiIjkPfXYiIiIiIhI3lNiIyIiIiIieU+JjYiIiIiI5D0lNiIiIiIikveU2IiIiIiISN5TYiMiIiIiInlPiY2IiIiIiOQ9JTYiIiIiIpL3lNiIiIiIiEje+//Iljd5fgY1igAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_record_curves(record_dict, sample_step=500):\n",
    "    # .set_index(\"step\") 将 step 列设置为 DataFrame 的索引\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    last_step = train_df.index[-1]  # 最后一步的步数\n",
    "\n",
    "    # print(train_df)\n",
    "    # print(val_df)\n",
    "\n",
    "    # 画图 \n",
    "    fig_num = len(train_df.columns)  # 画两张图,分别是损失和准确率\n",
    "\n",
    "    # plt.subplots：用于创建一个包含多个子图的图形窗口。\n",
    "    # 1：表示子图的行数为 1。\n",
    "    # fig_num：表示子图的列数，即子图的数量。\n",
    "    # figsize=(5 * fig_num, 5)：设置整个图形窗口的大小，宽度为 5 * fig_num，高度为 5。\n",
    "    # fig：返回的图形对象（Figure），用于操作整个图形窗口。\n",
    "    # axs：返回的子图对象（Axes 或 Axes 数组），用于操作每个子图。\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):\n",
    "        # train_df.index 是 x 轴数据（通常是 step）。\n",
    "        # train_df[item] 是 y 轴数据（当前指标的值）。\n",
    "        axs[idx].plot(train_df.index, train_df[item], label=\"train:\" + item)\n",
    "        # val_df.index 是 x 轴数据。\n",
    "        # val_df[item] 是 y 轴数据。\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=\"val:\" + item)\n",
    "        axs[idx].grid()  # 显示网格\n",
    "        axs[idx].legend()  # 显示图例\n",
    "        axs[idx].set_xticks(range(0, train_df.index[-1] + 1, 5000))  # 设置x轴刻度\n",
    "        axs[idx].set_xticklabels(map(lambda x: f\"{x // 1000}k\", range(0, last_step + 1, 5000)))  # 设置x轴标签\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "plot_record_curves(record_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d9729d15a0d01e8",
   "metadata": {},
   "source": [
    "## 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "3195e10a60c29806",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T04:39:08.188708Z",
     "iopub.status.busy": "2025-01-23T04:39:08.188523Z",
     "iopub.status.idle": "2025-01-23T04:39:11.132089Z",
     "shell.execute_reply": "2025-01-23T04:39:11.131576Z",
     "shell.execute_reply.started": "2025-01-23T04:39:08.188689Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test loss: 0.5088, Test acc: 0.8342\n"
     ]
    }
   ],
   "source": [
    "# 加载最好的模型\n",
    "# torch.load：加载保存的模型权重或整个模型。\n",
    "# \"checkpoints/best.ckpt\"：模型权重文件路径。\n",
    "# weights_only=True：仅加载模型的权重，而不是整个模型（包括结构和参数）。这是 PyTorch 2.1 引入的新特性，用于增强安全性。\n",
    "# map_location=device：将模型加载到当前设备（GPU或CPU）。\n",
    "model.load_state_dict(\n",
    "    torch.load(\"checkpoints/08_resnet_fine_tuning.ckpt\", weights_only=True, map_location=device))  # 加载最好的模型\n",
    "\n",
    "model.eval()  # 评估模式\n",
    "loss, acc = evaluate(model, eval_loader, loss_fct)\n",
    "print(f\"Test loss: {loss:.4f}, Test acc: {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a627399e1af63f81",
   "metadata": {},
   "source": [
    "## fine_tuning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "66f03ace24a39619",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T04:39:11.132960Z",
     "iopub.status.busy": "2025-01-23T04:39:11.132704Z",
     "iopub.status.idle": "2025-01-23T04:46:01.136643Z",
     "shell.execute_reply": "2025-01-23T04:46:01.136136Z",
     "shell.execute_reply.started": "2025-01-23T04:39:11.132940Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_377/1718245851.py:42: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
      "  state_dict = torch.load(ckpt_path, map_location=device)  # 加载模型参数\n",
      " 12%|█▏        | 8448/70400 [06:49<50:05, 20.61it/s, epoch=11]  "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 12 / global_step 8448\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# 因为前面的训练已经使得类内部的变量patience为5，故需要重新实例化一个对象\n",
    "early_stop_callback = EarlyStopCallback(patience=5, min_delta=0.01)\n",
    "\n",
    "# 再次训练\n",
    "model = ResNetCifar10.from_pretrained(\"checkpoints/08_resnet_fine_tuning.ckpt\", num_classes=len(class_names))  # 加载预训练模型\n",
    "model = model.to(device)\n",
    "\n",
    "# 微调（Fine-tuning）：在迁移学习或微调预训练模型时，这种方法特别有用。\n",
    "# 在这种情况下，你可能希望对模型的预训练部分（不包含\"cls\"的部分）使用较小的学习率，以避免破坏已经学到的特征。\n",
    "# 而对新添加的或需要特别训练的部分（如新的分类层，包含\"cls\"的部分）使用较高的学习率，以便更快地学习到特定任务的特征。\n",
    "# optimizer = torch.optim.Adam(model.parameters(), lr=0.001) 原始优化器\n",
    "optimizer = torch.optim.Adam(\n",
    "    [\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"cls\" not in key],\n",
    "            \"lr\": 0.0001  # 不需要重新训练的，学习率设为较小\n",
    "        },\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"cls\" in key],\n",
    "            \"lr\": 0.0005  # 需要重新训练的，学习率设为较大\n",
    "        }\n",
    "    ]\n",
    ")\n",
    "\n",
    "record_dict = training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    eval_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_loader)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c064d0e21bc0eefa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T04:46:01.137571Z",
     "iopub.status.busy": "2025-01-23T04:46:01.137246Z",
     "iopub.status.idle": "2025-01-23T04:46:01.298980Z",
     "shell.execute_reply": "2025-01-23T04:46:01.298486Z",
     "shell.execute_reply.started": "2025-01-23T04:46:01.137550Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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I7FarXz99dfs2LGDSy65hNTUVGJiYhg9ejRLliyp8njp6elVMjYGg4F//etfXHbZZdhsNvr27cuHH37YoDHa7XZuvfVWUlJSiIyM5PTTT2fNmjWB+48ePcp1111Hx44diYqKom/fvrz44ouAd1W3mTNn0rlzZyIjI+nRo0egCF1ERKQpCsvr142+NQivoGX9a0Q8fxaD9r8R6pGItAsej4dSR0VILh6Pp15jfPzxxxk3bhwzZszg4MGDHDx4kLS0NADuueceHn74YTZt2sSQIUMoLi5m8uTJLF26lO+++47zzz+fKVOmkJWVVedzzJ49m6uvvpoffviByZMnc91115GXlxe4Pz09nQceeKDW4++66y7eeecdXn75ZdatW0efPn2YNGlS4DHuvfdeNm7cyCeffMKmTZt45plnSE5OBuCJJ57gww8/5M0332TLli3897//JT09vV4/G5G27sml2/j9m99TFEZvvERai6+2Hebcuct4d92+UA+lXsJrepijGEPOBqLjw6v3gEi4KnO6GHTfpyF57o0PTsJmOfG/qPj4eCwWCzabLdCAcPPmzQA8+OCDTJgwIbBvYmIiQ4cODdx+6KGHeO+99/jwww/r7AMybdo0rr32WgD++te/8sQTT7B69WrOP/98AHr37h0IMo5XUlLCM888w0svvcQFF1wAwPPPP09mZiYvvPACd955J1lZWQwfPpxRo0YBVAlKsrKy6Nu3L6effjoGg4EePXqc8Gci0h787/sD/D1zKwAHC8p4cfporBGmEI9KpPVzutw8lrmVZ77YgccD/1m5h8uGd231DaXDK9MS7X1TYK0oCvFARCQc+IMAv+LiYu644w4GDhxIQkICMTExbNq06YSZliFDhgSuR0dHExcXR05OTmBbXc0Pd+zYgdPp5LTTTgtsM5vNjBkzhk2bNgFw00038frrrzNs2DDuuusuvvnmm8C+06ZNY/369fTv359bb72VxYsX1/8HINJG5RSVc+8HPwVuf7PjCBlvfo/bXb8MrUh7tT+/jJ89t5Knl3kDluvGdufVGae0+oAFwi3TYvMGLRYFLSItIspsYuODk0L23E11/Cpgd9xxB5mZmcydO5c+ffoQFRXFlVdeicPhqPNxzGZzldsGgwG3293k8fldcMEF7Nmzh4ULF5KZmcl5553HLbfcwty5cxkxYgS7du3ik08+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wsJud3NFRKQbUGwSaZ+SFum2TCYTY8aMYcyYMaxYsYLo6Gi2bt2Kj48PTU1NLered999bN68md69e2O1Wtvd58GDB7l06RL+/v4AFBUVERgYSFRU1G09FxER+XZQbBJpm6aHSbe0b98+fvOb3/CPf/yDkpIS3nvvPaqrq4mNjSUmJoZDhw5x9OhRzp49i8PhYM6cOYSGhjJ16lQKCgo4deoUeXl5/OxnP6OsrMy938bGRh5++GG++OILduzYQWZmJosWLdKcYRERuSbFJpH2aaRFuiWr1Up+fj7r1q2jpqaG6Ohofve73zFp0iQSEhLIy8sjISEBu93O7t27GT9+PPn5+WRkZJCamkptbS2RkZEkJSW1uLqVlJTEwIEDuf/++2loaCAtLY2VK1d67kRFRKTLUGwSaZ/J5XK5PN0IkW+D+fPn8/XXX7Nt2zZPN0VERARQbJJvD40LioiIiIiIoSlpERERERERQ9P0MBERERERMTSNtIiIiIiIiKEpaREREREREUNT0iIiIiIiIoampEVERERERAxNSYuIiIiIiBiakhYRERERETE0JS0iIiIiImJoSlpERERERMTQlLSIiIiIiIih/R/+vK5rwd+p2AAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 画图\n",
    "plot_record_curves(record_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "88d0503f867aa381",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-23T04:46:01.301596Z",
     "iopub.status.busy": "2025-01-23T04:46:01.301211Z",
     "iopub.status.idle": "2025-01-23T04:46:03.542577Z",
     "shell.execute_reply": "2025-01-23T04:46:03.542028Z",
     "shell.execute_reply.started": "2025-01-23T04:46:01.301566Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test loss: 0.4692, Test acc: 0.8416\n"
     ]
    }
   ],
   "source": [
    "# 评估\n",
    "model.load_state_dict(\n",
    "    torch.load(\"checkpoints/08_resnet_fine_tuning.ckpt\", weights_only=True, map_location=device))  # 加载最好的模型\n",
    "\n",
    "model.eval()  # 评估模式\n",
    "loss, acc = evaluate(model, eval_loader, loss_fct)\n",
    "print(f\"Test loss: {loss:.4f}, Test acc: {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "2138836e-9527-427f-859d-955d1f4815c3",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-23T04:47:24.932482Z",
     "iopub.status.busy": "2025-01-23T04:47:24.932098Z",
     "iopub.status.idle": "2025-01-23T04:47:25.058918Z",
     "shell.execute_reply": "2025-01-23T04:47:25.058344Z",
     "shell.execute_reply.started": "2025-01-23T04:47:24.932456Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "06_cifar_best.ckpt  08_resnet.ckpt\t\t09_inception_net_best.ckpt\n",
      "07_VGG.ckpt\t    08_resnet_fine_tuning.ckpt\n"
     ]
    }
   ],
   "source": [
    "!ls ./checkpoints/"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
